package com.ruoyi.business.service;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.business.Admin;
import com.ruoyi.business.AdminLogin;
import com.ruoyi.business.ao.AdminAO;
import com.ruoyi.business.enums.UsedIpEnum;
import com.ruoyi.business.mapper.AdminMapper;
import com.ruoyi.business.vo.AdminVO;
import com.ruoyi.common.common.CommonEnum;
import com.ruoyi.common.common.GlobalValue;
import com.ruoyi.common.common.ResultBody;
import com.ruoyi.common.exception.BizException;
import com.ruoyi.common.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author ：jiangguanjun
 * @description：管理员相关
 * @date ：2020/7/16 21:13
 */
@Slf4j
@Component
public class AdminService {

    @Autowired
    AdminMapper adminMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private AdminLoginService adminLoginService ;

    @Value("${login.image.able}")
    private Boolean imageAble  ;

    public ResultBody register(AdminAO adminAO) {
        String salt = RandomStringUtils.randomAlphanumeric(30);
        boolean b = this.checkImageCode(adminAO.getNike(), adminAO.getImageCode());

        if (!b) {
            return ResultBody.error(CommonEnum.REGISTER_IMAGE_CODE_ERROR);
        }
        Admin userDB = adminMapper.selectOne(new QueryWrapper<Admin>().eq("nike",adminAO.getNike()));
        if (userDB != null) {
            log.info("昵称已经存在：{}", userDB);
            return ResultBody.error(CommonEnum.REGISTER_NIKE_EXIST_ERROR);
        }
        String pass = MD5Util.getMD5String(adminAO.getPassword() + salt);
        adminAO.setPassword(pass);
        Admin admin = new Admin();
        BeanUtils.copyProperties(adminAO, admin);
        admin.setSalt(salt);
        // admin 信息
        int res = adminMapper.insert(admin);
        log.info("添加管理员结果：{}",res);
        if(res>0){
            return ResultBody.success("注册成功") ;
        }
        return ResultBody.error(CommonEnum.SERVER_BUSY);
    }

    /**
     * 登录
     *
     * @param adminAO
     * @return
     */
    @Transactional
    public ResultBody login(AdminAO adminAO) {
        //校验图片验证码
        if(imageAble){
            boolean b = this.checkImageCode(adminAO.getNike(), adminAO.getImageCode());
            if (!b) {
                return ResultBody.error(CommonEnum.REGISTER_IMAGE_CODE_ERROR);
            }
        }
        // 查找用户
        Admin adminDB = adminMapper.selectOne(new QueryWrapper<Admin>().eq("nike",adminAO.getNike()));
        if (adminDB.getId() == null) {
            log.info("用户不存在");
            return ResultBody.error(CommonEnum.LOGIN_NIKE_NOT_EXIST_ERROR);
        }
        String salt = adminDB.getSalt();
        String pass = MD5Util.getMD5String(adminAO.getPassword() + salt);
        // 校验密码是否正确，如果正确则生成token返回前端，  并记录登录信息，如果不正确则返回密码错误
        if (pass.equalsIgnoreCase(adminDB.getPassword())) {
            //过期时间 7 天

            Date expDate = DateUtil.getBeforTime(Calendar.DAY_OF_MONTH,1) ;
            HashMap<String, Object> jwtClaims = new HashMap<String, Object>() {};
            jwtClaims.put("userId", adminDB.getId()) ;
            String token = JwtUtil.createJWT(expDate, jwtClaims);
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("token", token);
            // 将token存入redis
            Long nowMill = System.currentTimeMillis() ;
            Long expMill = expDate.getTime() ;
            redisTemplate.opsForValue().set(token,token,expMill-nowMill, TimeUnit.MILLISECONDS);
            // 添加登录记录
            AdminLogin adminLogin = new AdminLogin() ;
            adminLogin.setaId(adminDB.getId());
            adminLogin.setIp(adminAO.getIp());
            if(adminDB.getIp() != null && !adminDB.getIp().equals(adminAO)){
                adminLogin.setUsedIp(UsedIpEnum.NO.getCode());
            }
            log.info("adminLogin::::::::{}",JSONObject.toJSONString(adminLogin));
            int res = adminLoginService.save(adminLogin) ;
            if(res<0){
                throw  new BizException(CommonEnum.LOGIN_ERROR) ;
            }
            return ResultBody.success(jsonObject);
        }

        return ResultBody.error(CommonEnum.LOGIN_PASSWORD_ERROR);
    }

    public ResultBody loginPhone(AdminAO adminAO) {
        //验证验证码是否正确
        String smsCode = adminAO.getSmsCode();
        String phone = adminAO.getPhone();
        boolean b = checkSmsCode(phone, smsCode);
        if (!b) {
            ResultBody.error(CommonEnum.LOGIN_SMS_CODE_ERROR);
        }
        //查询数据库是否有该用户
        Admin u = adminMapper.selectOne(new QueryWrapper<Admin>().eq("phone",phone));
        if (u == null) {
            return ResultBody.error(CommonEnum.LOGIN_PHONE_ERROR);
        }

        // 校验密码是否正确，如果正确则生成token返回前端， 并记录登录信息，如果不正确则返回密码错误
        //过期时间 7 天
        Date expDate = DateUtil.getBeforTime(Calendar.DAY_OF_MONTH,7) ;
        Admin finalU = u;
        HashMap<String, Object> jwtClaims = new HashMap<String, Object>(16) {};
        jwtClaims.put("userId", finalU.getId()) ;
        String token = JwtUtil.createJWT(expDate, jwtClaims);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("token", token);
        return ResultBody.success(jsonObject);
    }

    private boolean checkSmsCode(String phone, String smsCode) {
        String cacheSmsCode = (String) redisTemplate.opsForValue().get(GlobalValue.getSmsRedisKey(phone));
        if (StringUtils.isBlank(cacheSmsCode)) {
            return false;
        }
        if (smsCode.equalsIgnoreCase(cacheSmsCode)) {
            return true;
        }
        return false;
    }


    private boolean checkImageCode(String nike, String imageCode) {
        String key = GlobalValue.IMAGE_SESSION_KEY_FREFIX + nike;
        log.info("key:{}", key);
        String cacheCode = (String) redisTemplate.opsForValue().get(key);
        if (StringUtils.isBlank(cacheCode)) {
            return false;
        }
        log.info("缓存中的key:{};缓存中的value:{}", key, cacheCode);
        boolean b = cacheCode.equalsIgnoreCase(imageCode);
        log.info("比较结果：" + b);
        redisTemplate.opsForValue().set(key,cacheCode,1,TimeUnit.MILLISECONDS);
        return cacheCode.equalsIgnoreCase(imageCode);
    }


    public Admin getById(Integer id) {
        Admin admin = adminMapper.selectById(id);
        log.info("admin:{}", admin);
        return admin;
    }


    public List<AdminVO> getBatchByIds(Collection<Long> ids) throws InstantiationException, IllegalAccessException {
        List<Admin> userList = adminMapper.selectBatchIds(ids) ;
        List<AdminVO> userVOList = MyBeanUtils.convert2OtherCollection(userList,AdminVO.class) ;
        return userVOList ;
    }
}
